package com.tn.openrpc.stomp;

import java.net.URI;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kaazing.gateway.client.protocol.stomp.StompClient;
import com.kaazing.gateway.client.protocol.stomp.StompEvent;

/**
 * A factory that creates and connects a <code>StompClient</code>.
 */
public class StompClientFactory
{
  private static final Logger LOGGER = LoggerFactory.getLogger(StompClientFactory.class);

  private static final long DEFAULT_CONNECTION_TIMEOUT = 5 * 1000;

  /**
   * Creates a new <code>StompClient</code>.
   */
  public static StompClient newInstance(String location) throws Exception
  {
    return newInstance(location, null, null);
  }

  /**
   * Creates a new <code>StompClient</code>.
   */
  public static StompClient newInstance(String location, String username, String password) throws Exception
  {
    OpenListener openListener = new OpenListener();

    StompClient stompClient = new StompClient();
    stompClient.addStompListener(new LoggingStompListener());
    stompClient.addStompListener(openListener);
    stompClient.connect(new URI(location), username, password);

    long start = System.currentTimeMillis();
    while (!openListener.isOpen())
    {
      if (System.currentTimeMillis() > start + DEFAULT_CONNECTION_TIMEOUT)
      {
        throw new IllegalStateException("Failed to connect STOMP client. ");
      }

      LOGGER.debug("Waiting for STOMP client to open.");
      //Looks like there's a bug in removeStompListener that causes an exception to be thrown even though the listener being removed was
      //added a few lines above - Nick 11/6/2012.
      //stompClient.removeStompListener(openListener);
    }

    LOGGER.info("Created STOMP client: {}", stompClient);

    return stompClient;
  }

  /**
   * An implementation of <code>StompListener</code> that sets a flag when the <code>StompClient</code> is open.
   */
  private static class OpenListener extends NullStompListener
  {
    private boolean open = false;

    /**
     * Returns the open flag.
     */
    public boolean isOpen()
    {
      return open;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onOpen(StompEvent stompEvent)
    {
      this.open = true;
    }
  }
}
